﻿
namespace Sai.Test.Rules
{
    using System.Linq;
    using Sai.Core;
    using Sai.Core.Rules;
    using Sai.Test.TestDataBuilders;
    using Xunit;
    using NSubstitute;
    using Sai.Test.XUnit;

	public class CheckClassMethodsFacts
	{
		[Fact, TouchingFileSystemTest]
		public void Removing_Single_Method_Is_Flagged()
		{
			var oldClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account")
										.WithMethod("public void DoSomething() { }");

			string oldCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", oldClassBuilder);

			var newClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account");

            string newCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

			TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckTypeMethods())
                .Build();

			Assert.True(diff.HasChanged);
            Assert.Equal(1, diff.MethodsRemoved.Count);
            Assert.Equal(TypeChangeReason.MethodRemoved, diff.MethodsRemoved.First().Reason);
		}

		[Fact, TouchingFileSystemTest]
		public void Removing_Single_Method_From_Multiple_Is_Flagged()
		{
			var oldClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account")
										.WithMethod("public void DoSomething() { }")
										.WithMethod("public void DoSomethingElse() { }")
										.WithMethod("public void DoSomethingDifferent() { }");

            string oldCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", oldClassBuilder);

			var newClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account")
										.WithMethod("public void DoSomethingElse() { }")
										.WithMethod("public void DoSomethingDifferent() { }");

            string newCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

			TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckTypeMethods())
                .Build();

			Assert.True(diff.HasChanged);
            Assert.Equal(1, diff.MethodsRemoved.Count);
            Assert.Equal(TypeChangeReason.MethodRemoved, diff.MethodsRemoved.First().Reason);
		}

		[Fact, TouchingFileSystemTest]
		public void Removing_Templated_Method_Is_Flagged()
		{
			var oldClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account<T>")
										.WithMethod("public void DoSomething(IEnumerable<T> items) { }")
										.WithMethod("public void DoSomethingElse(IEnumerable<T> items) { }")
										.WithMethod("public void DoSomethingDifferent() { }");

            string oldCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", oldClassBuilder);

			var newClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account<T>")
										.WithMethod("public void DoSomethingElse(IEnumerable<T> items) { }")
										.WithMethod("public void DoSomethingDifferent() { }");

            string newCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

			TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckTypeMethods())
                .Build();

			Assert.True(diff.HasChanged);
            Assert.Equal(1, diff.MethodsRemoved.Count);
            Assert.Equal(TypeChangeReason.MethodRemoved, diff.MethodsRemoved.First().Reason);
		}

		[Fact, TouchingFileSystemTest]
		public void Marking_Method_As_Obsolete_Is_Flagged()
		{
			var oldClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account")
										.WithMethod("public void DoSomething() { }")
										.WithMethod("public void DoSomethingElse() { }")
										.WithMethod("public void DoSomethingDifferent() { }");

            string oldCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", oldClassBuilder);

			var newClassBuilder = CompilableClassBuilder.PublicClass()
										.Named("Account")
										.WithMethod("public void DoSomething() { }")
										.WithMethod("[Obsolete] public void DoSomethingElse() { }")
										.WithMethod("public void DoSomethingDifferent() { }");

			string newCode = BoilerPlateCodeBuilder.BuildFor("ApiEx", newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

			TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckTypeMethods())
                .Build();

			Assert.True(diff.HasChanged);
			Assert.Equal(1, diff.MethodsObsolete.Count);
            Assert.Equal(TypeChangeReason.MethodObsolete, diff.MethodsObsolete.First().Reason);
		}

	}
}
